﻿using System;
using System.Text.RegularExpressions;
using agsXMPP;
using agsXMPP.protocol.client;
using sharpxbot.Core.Plugins.Muc;
using sharpxbot.Core.Security;
using sharpxbot.Plugins.Base;
using sharpxbot.Plugins.Context;
using sharpxbot.Utils.Logging;

namespace sharpxbot.Core.Plugins
{
    public class MucAdminPlugin : AbstractPlugin
    {
        private static readonly Guid PluginGuid = new Guid("a0c157f7-9d8d-4e79-80d9-ba29e1349778");

        private const string MucCommandPattern = "muc";
        private readonly Regex commandTypeRegex = new Regex(@"^muc (?<command>\w+) ");
        private readonly Regex kickAndBanCommandRegex = new Regex(@"^muc[ ](?<command>\w+)[ ](?<muc_jid>[^\s]+)[ ](?<reason>.+)$");
        private readonly Regex suspendRoomRegex = new Regex(@"^muc suspend (?<room_jid>[^\s]+) (?<timeout>\d+)$");

        public override PluginPermissions NeededPermissions
        {
            get { return PluginPermissions.PluginOwner; }
        }

        public override string Name
        {
            get { return "MucAdminPlugin"; }
        }

        public override string Author
        {
            get { return "tillias"; }
        }

        public override Guid GUID
        {
            get { return PluginGuid; }
        }

        public override string Description
        {
            get { return "Allows to perform administrative group-chat actions"; }
        }

        public override string Usage
        {
            get { return "Usage not yet implemented"; }
        }

        public MucAdminPlugin(IPluginContext context)
            : base(context) { }

        public override void ProcessMessage(Message message)
        {
            if (message == null)
                return;
            if (message.Type == MessageType.chat && message.From.Bare == Context.OwnerJid) // only owner can use admin commands. Todo -- grant to admins in group-chats
            {
                IMucCommand command = ParseCommand(message.Body);
                if (command != null)
                {
                    try
                    {
                        command.Execute(Context);
                    }
                    catch (Exception ex)
                    {
                        Logger.Write("Exception while executing muc command", ex, LogMessageType.Error);
                    }
                }
            }
        }

        public override void ProcessPresence(Presence presence)
        {
            //nothing todo here
        }

        private IMucCommand ParseCommand(string str)
        {
            IMucCommand result = null;

            if (!str.StartsWith(MucCommandPattern))
                return null;

            try
            {
                Match m = commandTypeRegex.Match(str);
                if (m.Success)
                {
                    string cmdTypeStr = m.Groups["command"].Value;
                    MucCommandEnum commandType = GetCommandType(cmdTypeStr);

                    switch (commandType)
                    {
                        case MucCommandEnum.Kick:
                            result = GetKickCommand(str);
                            break;
                        case MucCommandEnum.SuspendRoom:
                            result = GetSuspendCommand(str);
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Write("Exception while parsing muc command", ex, LogMessageType.Error);
            }

            return result;
        }

        private MucCommandEnum GetCommandType(string str)
        {
            MucCommandEnum result = MucCommandEnum.Unknown;

            try
            {
                switch (str.ToUpper())
                {
                    case "KICK":
                        result = MucCommandEnum.Kick;
                        break;
                    case "BAN":
                        result = MucCommandEnum.Ban;
                        break;
                    case "SUSPEND":
                        result = MucCommandEnum.SuspendRoom;
                        break;
                }
            }
            catch { }

            return result;
        }

        #region Command Factory

        private IMucCommand GetKickCommand(string str)
        {
            IMucCommand result = null;

            try
            {
                Match m = kickAndBanCommandRegex.Match(str);
                if (m.Success)
                {
                    result = new KickCommand()
                    {
                        CommandType = MucCommandEnum.Kick,
                        MucJid = new Jid(m.Groups["muc_jid"].Value),
                        Reason = m.Groups["reason"].Value
                    };
                }
            }
            catch { }

            return result;
        }

        private IMucCommand GetSuspendCommand(string str)
        {
            IMucCommand result = null;

            try
            {
                Match m = suspendRoomRegex.Match(str);
                if (m.Success)
                {
                    result = new SuspendRoomCommand()
                    {
                        CommandType = MucCommandEnum.SuspendRoom,
                        RoomBareJid = m.Groups["room_jid"].Value,
                        Timeout = Int32.Parse( m.Groups["timeout"].Value) * 1000 // seconds into milliseconds
                    };
                }
            }
            catch { }

            return result;
        }

        #endregion
    }
}
